﻿using Microsoft.EntityFrameworkCore;
using Sgr.Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace Sgr.Domain.Repositories
{
    /// <summary>
    /// IQueryable扩展方法
    /// </summary>
    public static class QueryableExtensions
    {
        #region IMustHaveOrg 扩展查询

        /// <summary>
        /// 获取指定组织下的所有实体
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="query">查询对象</param>
        /// <param name="orgId">组织ID</param>
        /// <param name="predicate">额外的查询条件</param>
        /// <param name="tracking">是否跟踪实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>实体列表</returns>
        public static async Task<IEnumerable<TEntity>> GetByOrgIdAsync<TEntity>(
            this IQueryable<TEntity> query,
            long orgId,
            Expression<Func<TEntity, bool>>? predicate = null,
            bool tracking = true,
            CancellationToken cancellationToken = default)
            where TEntity : class, IMustHaveOrg<long>
        {
            if (!tracking)
                query = query.AsNoTracking();

            // 添加组织ID过滤
            query = query.Where(x => x.OrgId == orgId);

            // 添加额外的查询条件
            if (predicate != null)
                query = query.Where(predicate);

            return await query.ToArrayAsync(cancellationToken);
        }

        /// <summary>
        /// 分页获取指定组织下的实体
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="query">查询对象</param>
        /// <param name="orgId">组织ID</param>
        /// <param name="skipCount">跳过数量</param>
        /// <param name="maxResultCount">最大返回数量</param>
        /// <param name="predicate">额外的查询条件</param>
        /// <param name="orderBy">排序表达式</param>
        /// <param name="tracking">是否跟踪实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>分页结果</returns>
        public static async Task<(IEnumerable<TEntity> Items, long TotalCount)> GetPagedByOrgIdAsync<TEntity>(
            this IQueryable<TEntity> query,
            long orgId,
            int skipCount,
            int maxResultCount,
            Expression<Func<TEntity, bool>>? predicate = null,
            Expression<Func<TEntity, object>>? orderBy = null,
            bool tracking = true,
            CancellationToken cancellationToken = default)
            where TEntity : class, IMustHaveOrg<long>
        {
            if (!tracking)
                query = query.AsNoTracking();

            // 添加组织ID过滤
            query = query.Where(x => x.OrgId == orgId);

            // 添加额外的查询条件
            if (predicate != null)
                query = query.Where(predicate);

            var totalCount = await query.LongCountAsync(cancellationToken);

            if (orderBy != null)
                query = query.OrderBy(orderBy);

            var items = await query
                .Skip(skipCount)
                .Take(maxResultCount)
                .ToArrayAsync(cancellationToken);

            return (items, totalCount);
        }

        #endregion IMustHaveOrg 扩展查询

        #region IHaveCode 扩展查询

        /// <summary>
        /// 根据编码获取实体
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="query">查询对象</param>
        /// <param name="code">编码</param>
        /// <param name="tracking">是否跟踪实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>实体对象，不存在返回null</returns>
        public static async Task<TEntity?> GetByCodeAsync<TEntity>(
            this IQueryable<TEntity> query,
            string code,
            bool tracking = true,
            CancellationToken cancellationToken = default)
            where TEntity : class, IHaveCode
        {
            Check.StringNotNullOrEmpty(code, nameof(code));

            if (!tracking)
                query = query.AsNoTracking();

            return await query
                .FirstOrDefaultAsync(x => x.Code == code, cancellationToken);
        }

        /// <summary>
        /// 检查编码是否唯一
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <typeparam name="TPrimaryKey">TPrimaryKey</typeparam>
        /// <param name="query">查询对象</param>
        /// <param name="code">编码</param>
        /// <param name="excludedId">需要排除的ID（用于编辑场景）</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>true: 编码唯一; false: 编码已存在</returns>
        public static async Task<bool> CodeIsUniqueAsync<TEntity, TPrimaryKey>(
            this IQueryable<TEntity> query,
            string code,
            TPrimaryKey? excludedId = default,
            CancellationToken cancellationToken = default)
            where TEntity : EntityHaveDomainEvent<TPrimaryKey>, IHaveCode
        {
            Check.StringNotNullOrEmpty(code, nameof(code));

            query = query.AsNoTracking()
                .Where(x => x.Code == code);

            if (excludedId != null)
            {
                query = query.Where(x => !x.Id!.Equals(excludedId));
            }

            return !await query.AnyAsync(cancellationToken);
        }

        #endregion IHaveCode 扩展查询

        #region ISoftDelete 扩展查询

        /// <summary>
        /// 获取未删除的实体列表
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="query">查询对象</param>
        /// <param name="predicate">查询条件</param>
        /// <param name="tracking">是否跟踪实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>实体列表</returns>
        public static async Task<IEnumerable<TEntity>> GetNotDeletedAsync<TEntity>(
            this IQueryable<TEntity> query,
            Expression<Func<TEntity, bool>>? predicate = null,
            bool tracking = true,
            CancellationToken cancellationToken = default)
            where TEntity : class, ISoftDelete
        {
            query = query.Where(x => !x.IsDeleted);

            if (!tracking)
                query = query.AsNoTracking();

            if (predicate != null)
                query = query.Where(predicate);

            return await query.ToArrayAsync(cancellationToken);
        }

        /// <summary>
        /// 分页获取未删除的实体
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="query">查询对象</param>
        /// <param name="skipCount">跳过数量</param>
        /// <param name="maxResultCount">最大返回数量</param>
        /// <param name="predicate">查询条件</param>
        /// <param name="orderBy">排序表达式</param>
        /// <param name="tracking">是否跟踪实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>分页结果</returns>
        public static async Task<(IEnumerable<TEntity> Items, long TotalCount)> GetPagedNotDeletedAsync<TEntity>(
            this IQueryable<TEntity> query,
            int skipCount,
            int maxResultCount,
            Expression<Func<TEntity, bool>>? predicate = null,
            Expression<Func<TEntity, object>>? orderBy = null,
            bool tracking = true,
            CancellationToken cancellationToken = default)
            where TEntity : class, ISoftDelete
        {
            query = query.Where(x => !x.IsDeleted);

            if (!tracking)
                query = query.AsNoTracking();

            if (predicate != null)
                query = query.Where(predicate);

            var totalCount = await query.LongCountAsync(cancellationToken);

            if (orderBy != null)
                query = query.OrderBy(orderBy);

            var items = await query
                .Skip(skipCount)
                .Take(maxResultCount)
                .ToArrayAsync(cancellationToken);

            return (items, totalCount);
        }

        #endregion ISoftDelete 扩展查询
    }
}